﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using System.Web.Hosting;

namespace TanashCMS.Business.Task
{
    public class SitePublishTask
    {
        private TanashWebsite _website;
        private string AssetFolder { get { return GetPath(_website.WebsiteFolder); } }
        private string EncodedAssetUrl { get { return System.Web.HttpUtility.UrlPathEncode(_website.WebsiteFolder); } }
        public SitePublishTask(TanashWebsite website)
        {
            _website = website;
        }
        public void WriteXML()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.NewLineHandling = NewLineHandling.Entitize;
            settings.Indent = true;

            string systemXmlPath = System.Web.Hosting.HostingEnvironment.MapPath(_website.XmlPath);

            if (!Directory.Exists(Path.GetDirectoryName(systemXmlPath)))
                Directory.CreateDirectory(Path.GetDirectoryName(systemXmlPath));

            // Create a new XmlTextWriter instance
            FileStream fs = new FileStream(GetPath(Path.Combine(@"\customassets\", _website.XmlPath)), FileMode.Create);

            XmlWriter w = XmlWriter.Create(fs, settings);

            w.WriteStartDocument();
            w.WriteStartElement("website");
            w.WriteAttributeString("name", _website.Title);
            w.WriteAttributeString("hostname", _website.HostHeader);
            w.WriteAttributeString("systemName", _website.SubFolderName);
            w.WriteAttributeString("isOnline", _website.IsOnline ? "1" : "0");
            w.WriteAttributeString("isBlogSite", _website.getOptionValue("IsBlogSite"));
            w.WriteAttributeString("url", _website.URL);
            w.WriteAttributeString("publishDate", string.Format("{0:ddd, dd MMM yyyy hh:mm:ss}", TimeZoneTask.ToLocal(_website.DifferenceFromGMT, DateTime.Now)));
            w.WriteAttributeString("lastBuildDate", string.Format("{0:ddd, dd MMM yyyy hh:mm:ss}", TimeZoneTask.ToLocal(_website.DifferenceFromGMT, DateTime.Now)));

            // web pages
            List<WebPage> pages = WebPage.List(_website.ID, false);
            writeWebPageXml(w, "webpage", _website, pages);

            // blog posts
            List<WebPage> blogposts = WebPage.GetPublishedBlogPosts(_website.ID);
            writeWebPageXml(w, "blogpost", _website, blogposts);

            // navigation
            writeNavigationXml(w, _website, Navigation.ListTopLevel(_website.ID));

            // inventory
            List<Category> categories = Category.List(_website.ID, 0);
            w.WriteStartElement("inventory");
            writeCategoryXml(w, _website, categories);

            // products in no category

            List<Product> products = Product.List(_website.ID, 0);
            foreach (Product product in products)
            {
                WriteProductXml(w, product);
            }


            w.WriteEndElement();
            w.WriteEndElement();
            w.WriteEndDocument();
            w.Close();

            fs.Close();
            fs.Dispose();
        }

        private void writeWebPageXml(XmlWriter w, string ElementName, TanashWebsite website, List<WebPage> pages)
        {
            foreach (WebPage page in pages)
            {
                w.WriteStartElement(ElementName);
                w.WriteAttributeString("id", page.ID.ToString());
                w.WriteAttributeString("key", page.ItemKey);
                w.WriteAttributeString("guid", page.GUID.ToString());
                w.WriteAttributeString("title", page.Title);
                w.WriteAttributeString("dateCreated", string.Format("{0:ddd, dd MMM yyyy hh:mm:ss}", TimeZoneTask.ToLocal(website.DifferenceFromGMT, page.DateCreated)));
                w.WriteAttributeString("createdYear", page.DateCreated.Year.ToString());
                w.WriteAttributeString("createdMonth", page.DateCreated.Month.ToString());
                w.WriteAttributeString("createdDay", page.DateCreated.Day.ToString());
                w.WriteAttributeString("createdHour", page.DateCreated.Hour.ToString());
                w.WriteAttributeString("createdMinute", page.DateCreated.Minute.ToString());
                w.WriteAttributeString("secure", page.IsSecure ? "1" : "0");
                w.WriteAttributeString("pageType", page.PageType.ToString());
                w.WriteAttributeString("masterPage", page.MasterPage);
                w.WriteAttributeString("homepage", website.HomePageID == page.ID ? "1" : "0");
                w.WriteAttributeString("blogpost", page.IsBlogPost ? "1" : "0");
                w.WriteAttributeString("publishDate", string.Format("{0:ddd, dd MMM yyyy hh:mm:ss}", TimeZoneTask.ToLocal(website.DifferenceFromGMT, DateTime.Now)));

                if (page.PageType == WebPageType.SmartPage)
                {
                    w.WriteStartElement("components");
                    List<SmartPageComponent> components = (List<SmartPageComponent>)Configuration.GetCurrentSession().CreateQuery("select c from SmartPageComponent c where c.WebPageID = " + page.ID.ToString() + " order by c.SlotIndex").List<SmartPageComponent>();
                    foreach (SmartPageComponent component in components)
                    {
                        w.WriteStartElement("component");
                        w.WriteAttributeString("id", component.ID.ToString());
                        w.WriteAttributeString("guid", component.GUID);
                        w.WriteAttributeString("type", component.ComponentType.ToString());
                        w.WriteAttributeString("index", component.SlotIndex.ToString());
                        w.WriteAttributeString("objectType", component.SourceObjectType.ToString());
                        w.WriteAttributeString("objectID", component.SourceObjectID.ToString());
                        w.WriteAttributeString("userControlName", component.UserControlName);
                        if (component.HtmlContent != "")
                            w.WriteCData(component.HtmlContent);
                        w.WriteEndElement();
                    }
                    w.WriteEndElement();
                }

                List<WebPage> children = WebPage.List(website.ID, page.ID);
                if (children.Count > 0)
                    writeWebPageXml(w, ElementName, website, children);

                if (page.HTMLContent != null)
                {
                    if (page.HTMLContent != "")
                        w.WriteCData(page.HTMLContent);
                }
                w.WriteEndElement();
            }
        }

        private void writeCategoryXml(XmlWriter w, TanashWebsite website, List<Category> categories)
        {
            string imagesFolder = AssetFolder + "\\Image\\";
            string imagesUrl = EncodedAssetUrl + "/image";
            foreach (Category cat in categories)
            {
                w.WriteStartElement("category");
                w.WriteAttributeString("id", cat.ID.ToString());
                w.WriteAttributeString("guid", cat.GUID);
                w.WriteAttributeString("title", cat.Title);
                w.WriteAttributeString("key", cat.ItemKey);
                w.WriteAttributeString("PhotoURL", imagesUrl.TrimEnd('/') + cat.PhotoURL);
                //string thumbnailUrl = "";
                //if (getThumbnail(imagesFolder, imagesUrl.TrimEnd('/') + cat.PhotoURL, out thumbnailUrl))
                    //w.WriteAttributeString("thumbnail", thumbnailUrl);

                List<Category> children = Category.List(cat.WebsiteID, cat.ID);
                if (children.Count > 0)
                    writeCategoryXml(w, website, children);

                List<Product> products = Product.List(website.ID, cat.ID);
                foreach (Product product in products)
                {
                    WriteProductXml(w, product);
                }
                w.WriteEndElement();
            }
        }

        [Obsolete("no longer generating thumbnails at upload time")]
        private bool getThumbnail(string imagesFolder, string fullSizeImageUrl, out string thumbnailUrl)
        {
            thumbnailUrl = "";
            return false;
        }

        private void WriteProductXml(XmlWriter w, Product product)
        {
            string imagesFolder = AssetFolder + "\\Image\\";
            string imagesUrl = EncodedAssetUrl + "/image";
            w.WriteStartElement("product");
            w.WriteAttributeString("id", product.ID.ToString());
            w.WriteAttributeString("title", product.Title);
            w.WriteAttributeString("key", product.ItemKey);
            w.WriteAttributeString("guid", product.GUID);
            w.WriteAttributeString("UPC", product.UPC);
            w.WriteAttributeString("Price", product.Price.ToString());
            w.WriteAttributeString("Discount", product.Discount.ToString());
            w.WriteAttributeString("PhotoURL", imagesUrl.TrimEnd('/') + product.PhotoURL);
            //string thumbnailUrl = "";
            //if (getThumbnail(imagesFolder, imagesUrl.TrimEnd('/') + product.PhotoURL, out thumbnailUrl))
                //w.WriteAttributeString("thumbnail", System.Web.HttpUtility.UrlEncode(thumbnailUrl));

            List<ProductOption> options = ProductOption.List(product.ID);
            foreach (ProductOption option in options)
            {
                w.WriteStartElement("option");
                w.WriteAttributeString("id", option.ID.ToString());
                w.WriteAttributeString("guid", option.GUID);
                w.WriteAttributeString("typeid", option.OptionType.ID.ToString());
                w.WriteAttributeString("title", option.OptionType.Title);
                w.WriteValue(option.Value);
                w.WriteEndElement();
            }

            if (product.HTMLContent != null)
            {
                if (product.HTMLContent != "")
                    w.WriteCData(product.HTMLContent);
            }
            w.WriteEndElement();
        }

        private void writeNavigationXml(XmlWriter w, TanashWebsite website, IList<Navigation> navigation)
        {
            foreach (Navigation navItem in navigation)
            {
                w.WriteStartElement("navigation");
                w.WriteAttributeString("id", navItem.ID.ToString());
                w.WriteAttributeString("guid", navItem.GUID);
                w.WriteAttributeString("targetType", navItem.TargetType.ToString());
                w.WriteAttributeString("targetID", navItem.TargetID.ToString());
                CMSDataObject target = navItem.GetTarget();
                if (target != null) w.WriteAttributeString("navigateURL", target.GetUrl());
                w.WriteValue(navItem.Title);
                IList<Navigation> children = Navigation.ListChildren(website.ID, navItem.ID);
                writeNavigationXml(w, website, children);
                w.WriteEndElement();
            }
        }

        public string getWebsiteXml(int WebsiteID)
        {
            TanashWebsite website = Configuration.GetCurrentSession().Get<TanashWebsite>(WebsiteID);
            if (!File.Exists(GetPath(website.XmlPath)))
                WriteXML();

            return GetPath(website.XmlPath);
        }

        public void writeImagesToXml()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.NewLineHandling = NewLineHandling.Entitize;
            settings.Indent = true;

            // something might have screwed up
            if (_website == null) throw new InvalidOperationException("Can't write image xml, website is null");

            // Create a new XmlTextWriter instance
            FileStream fs = new FileStream(GetPath(_website.ImagesXmlPath), FileMode.Create);

            XmlWriter w = XmlWriter.Create(fs, settings);

            DirectoryInfo folder = new DirectoryInfo(AssetFolder + @"\images");

            w.WriteStartDocument();
            w.WriteStartElement("media");
            w.WriteStartElement("folder");
            w.WriteAttributeString("path", folder.FullName);
            writeImageFolders(w, folder.GetDirectories(), "/");
            writeFiles(w, folder.GetFiles("*.*"), "/");
            w.WriteValue(folder.Name);
            w.WriteEndElement();
            w.WriteEndElement();

            w.WriteEndDocument();
            w.Close();

            fs.Close();
            fs.Dispose();
        }

        private void writeImageFolders(XmlWriter w, DirectoryInfo[] folders, string baseUrl)
        {
            foreach (DirectoryInfo folder in folders)
            {
                w.WriteStartElement("folder");
                w.WriteAttributeString("path", folder.FullName);
                w.WriteValue(folder.Name);
                writeImageFolders(w, folder.GetDirectories(), baseUrl + folder.Name + "/");
                writeFiles(w, folder.GetFiles("*.*"), baseUrl + folder.Name + "/");
                w.WriteEndElement();
            }
        }

        private void writeFiles(XmlWriter w, FileInfo[] files, string baseUrl)
        {
            foreach (FileInfo file in files)
            {
                if (file.Name.Contains("_200.png") || file.Name.Contains("_100.png"))
                    continue;

                System.Drawing.Image img = null;
                try
                {
                    img = System.Drawing.Image.FromFile(file.FullName);
                }
                catch
                {
                }

                w.WriteStartElement("image");
                w.WriteAttributeString("systemPath", file.FullName);
                w.WriteAttributeString("path", System.Web.HttpUtility.UrlPathEncode(baseUrl));
                w.WriteAttributeString("extension", file.Extension);
                w.WriteAttributeString("fileName", Path.GetFileNameWithoutExtension(file.Name));
                if (File.Exists(file.Directory.FullName + "/" + Path.GetFileNameWithoutExtension(file.Name) + "_200.png"))
                    w.WriteAttributeString("thumbnail", Path.GetFileNameWithoutExtension(file.Name) + "_200.png");
                if (img != null)
                {
                    w.WriteAttributeString("width", img.Width.ToString());
                    w.WriteAttributeString("height", img.Height.ToString());
                }
                w.WriteValue(file.Name);
                w.WriteEndElement();
            }
        }

        public string getNavigationHtml()
        {
            // load navigation
            string appPath = "/TanashCMS";

            XslCompiledTransform xsl = new XslCompiledTransform(false);
            xsl.Load(GetPath("\\xsl\\navigation.xsl"));

            XsltArgumentList args = new XsltArgumentList();
            args.AddParam("currentUrl", "", appPath + "/" + "currenturl");

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            StringWriter sw = new StringWriter(sb);
            xsl.Transform(_website.XmlPath, args, sw);

            sw.Close();

            return sb.ToString();
        }

        public static string GetPath(string virtualPath)
        {
            return HostingEnvironment.MapPath(virtualPath);
        }
    }
}
